package com.ruoyi.service;


import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.mapper.SysUserMapper;
import com.ruoyi.common.flowable.FlowServiceFactory;
import com.ruoyi.common.flowable.TaskCandidateUserForStaticAnalysis;
import com.ruoyi.common.flowable.expression.SimpleVariableScope;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.entity.ActReDeployment;
import com.ruoyi.entity.ActReProcdef;
import com.ruoyi.mapper.ActReProcdefMapper;
import com.ruoyi.vo.NextPotentialApproversVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngines;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author XuanXuan
 *
 **/
@Service
@Slf4j
public class NextApproverService extends FlowServiceFactory {
    private static final Log logger = LogFactory.getLog(NextApproverService.class);
    @Autowired
    protected ActReProcdefMapper actReProcdefMapper;
    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    TaskCandidateUserForStaticAnalysis taskCandidateUser;

    @Qualifier("processEngine")
    @Resource
    protected ProcessEngine processEngine;

    /**
     * 静态分析获取下一个审批人
     */
    public NextPotentialApproversVO getNextPotentialApprovers(String processDefinitionType, String currentTaskId, Map processVariables) {
        ActReDeployment actReDeployment;
        ActReProcdef actReProcdef;
        String processDefinitionId;

        NextPotentialApproversVO nextPotentialApproversVO = new NextPotentialApproversVO();
        if (StrUtil.isNotBlank(currentTaskId)) {
            Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult();
            if(currentTask == null){
                return nextPotentialApproversVO;
            }
            actReProcdef = actReProcdefMapper.getById(currentTask.getProcessDefinitionId());
            actReDeployment = actReDeploymentMapper.getById(actReProcdef.getDeploymentId());
            processDefinitionId = actReProcdef.getId();
        } else {
            actReDeployment = actReDeploymentMapper.getEnterpriseFlow(processDefinitionType);
            actReProcdef = actReProcdefMapper.getByDeploymentId(actReDeployment.getId());
            Assert.isFalse(actReProcdef == null, "请先配置对应业务的流程图");
            processDefinitionId = actReProcdef.getId();
        }
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        nextPotentialApproversVO.setActReDeployment(actReDeployment)
                .setActReProcdef(actReProcdef)
                .setProcessDefinitionType(processDefinitionType)
                .setCurrentTaskId(currentTaskId)
                .setProcessVariables(processVariables)
                .setBpmnModel(bpmnModel);

        SysUser user = SecurityUtils.getLoginUser().getUser();
        SysDept dept = user.getDept();
        Map variables = nextPotentialApproversVO.getProcessVariables();
        variables.putAll(processVariables);
        if (StrUtil.isBlank(currentTaskId)) {
            variables.put("startUserId", user.getUserId());
        }
        variables.put("startDeptCode", dept.getOrgNo());
        variables.put("lastDeptCode", dept.getOrgNo());
        variables.put("lastAuditUserId", user.getUserId() + "");

        FlowElement startElement;
        if (StrUtil.isBlank(currentTaskId)) {
            Process process = bpmnModel.getMainProcess(); // 获取主流程
            startElement = process.findFlowElementsOfType(StartEvent.class).iterator().next();
        } else { //审批
            Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult();
            if (currentTask == null) {
                logger.warn("Task with ID {} not found." + currentTaskId);
                return nextPotentialApproversVO;
            }
            String currentTaskDefinitionKey = currentTask.getTaskDefinitionKey();
            startElement = bpmnModel.getFlowElement(currentTaskDefinitionKey);
            nextPotentialApproversVO.setCurrentTask(currentTask)
                    .setCurrentTaskDefinitionKey(currentTaskDefinitionKey);
        }
        nextPotentialApproversVO.setCurrentElement(startElement);

        traverseFlowElements(startElement, nextPotentialApproversVO);

        return nextPotentialApproversVO;
    }

    /**
     * 遍历流程元素，寻找下一个节点
     */
    private void traverseFlowElements(FlowElement currentElement, NextPotentialApproversVO nextPotentialApproversVO) {
        BpmnModel bpmnModel = nextPotentialApproversVO.getBpmnModel();
        System.out.println("Visiting element: " + currentElement.getId() + " - " + currentElement.getName());

        if (currentElement instanceof FlowNode) {
            List<SequenceFlow> outgoingFlows = ((FlowNode) currentElement).getOutgoingFlows();
            List<SequenceFlow> outgoingFlowsWithCondition = outgoingFlows.stream().filter(r -> StrUtil.isNotBlank(r.getConditionExpression())).collect(Collectors.toList());
            List<SequenceFlow> outgoingFlowsDefault = outgoingFlows.stream().filter(r -> StrUtil.isBlank(r.getConditionExpression())).collect(Collectors.toList());
            UserTask userTask = null;
            boolean nextIsEnd = false;
            for (SequenceFlow outgoingFlow : outgoingFlowsWithCondition) {
                String conditionExpression = outgoingFlow.getConditionExpression();
                if (conditionExpression == null || evaluateCondition(conditionExpression, nextPotentialApproversVO.getProcessVariables())) {
                    FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef());
                    // 假设 evaluateCondition 是一个函数，用于评估给定的条件表达式和流程变量。
                    if (targetElement instanceof UserTask) {
                        userTask = (UserTask) targetElement;
                        break;
                    } else if (targetElement instanceof ExclusiveGateway) {
                        traverseFlowElements(targetElement, nextPotentialApproversVO);
                    } else if (targetElement instanceof EndEvent) {
                        nextIsEnd = true;
                    }
                }
            }
            if (outgoingFlowsDefault.size() > 0 && userTask == null) {
                for (SequenceFlow outgoingFlow : outgoingFlowsDefault) {
                    FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef());
                    if (targetElement instanceof UserTask) {
                        userTask = (UserTask) targetElement;
                    } else if (targetElement instanceof ExclusiveGateway) {
                        traverseFlowElements(targetElement, nextPotentialApproversVO); // 继续递归遍历
                    } else if (targetElement instanceof EndEvent) {
                        nextIsEnd = true;
                    }
                }
            }
            nextPotentialApproversVO.setNextIsEnd(nextIsEnd);
            if (userTask != null) {
                nextPotentialApproversVO.setNextUserTask(userTask);
                getCandidatesFromUserTask(nextPotentialApproversVO);
                String lastAuditUserId = (String) nextPotentialApproversVO.getProcessVariables().get("lastAuditUserId");
                long count = nextPotentialApproversVO.getPotentialApprovers().stream().filter(r -> r.get("value").equals(lastAuditUserId)).count();
                if (count > 0) { //  如果当前节点的候选者中包含上一节点的审批人，继续往后寻找
                    traverseFlowElements(userTask, nextPotentialApproversVO);
                }
            }
        }
    }

    /**
     * 获取用户任务节点的候选者
     */
    private void getCandidatesFromUserTask(NextPotentialApproversVO nextPotentialApproversVO) {
        UserTask userTask = nextPotentialApproversVO.getNextUserTask();
        Task task = nextPotentialApproversVO.getCurrentTask();
        TaskCandidateUserForStaticAnalysis.CandidateUserHandle candidateUserHandle = taskCandidateUser.getCandidateUserHandle(userTask, task, nextPotentialApproversVO.getProcessVariables());
        List<String> users = candidateUserHandle.getUsers();
        if (users.isEmpty()){
            nextPotentialApproversVO.setPotentialApprovers(new ArrayList<>());
            return;
        }
        List<SysUser> userList = userMapper.selectBatchIds(users);
        List candidates = userList.stream().map(r -> {
            Map map = new HashMap();
            map.put("value", r.getUserId() + "");
            map.put("label", r.getNickName() + "(" + r.getDeptName() + ")");
            return map;
        }).collect(Collectors.toList());
        nextPotentialApproversVO.setPotentialApprovers(candidates);
    }

    private Object resolveExpression(String expressionString, Map<String, Object> variables) {
        if (!StringUtils.isNotBlank(expressionString)) {
            return null;
        }
        // 默认情况下，会自动构建并返回默认的流程引擎：ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        // 从processEngine获取配置实例
        ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
        // Flowable's ExpressionManager handles both simple ${var} and complex expressions with beans
        Expression expression = processEngineConfiguration.getExpressionManager()
                .createExpression(expressionString);
        try {
            // 创建 VariableScope 并设置变量
            SimpleVariableScope variableScope = new SimpleVariableScope();
            variableScope.setVariables(variables);
            return expression.getValue(variableScope);
        } catch (Exception e) {
            logger.warn("Could not resolve expression: '{}' with variables. Error: {}. Returning expression string itself." +
                    expressionString + e.getMessage());
            // If it's not an expression (e.g., a literal user/group ID), it might throw an exception.
            // In that case, the original string is likely the literal value.
            return expressionString;
        }
    }

    private boolean evaluateCondition(String conditionExpression, Map<String, Object> variables) {
        if (!StringUtils.isNotBlank(conditionExpression)) {
            return false; // No condition means not true (unless it's a default flow)
        }
        Object result = resolveExpression(conditionExpression, variables);
        if (result instanceof Boolean) {
            return (Boolean) result;
        } else if (result instanceof String) {
            // Sometimes conditions might resolve to "true" or "false" as strings
            return Boolean.parseBoolean((String) result);
        }
        logger.warn("Condition expression '{}' did not evaluate to a Boolean. Result: {}" + conditionExpression + result);
        return false;
    }
}